import { Controller } from 'egg';
const { envConfig } = require('../appConfig.js')
const Sequelize = require('sequelize');
const CryptoJS = require('crypto-js');
const { userMsg } = require('../middleware/user/requestUserMsg.js');
const moment = require('moment');
const artTemplate = require('art-template');
const path = require('path');
const superagent = require('superagent');
require('colors');
let Op = Sequelize.Op;

export default class UserController extends Controller {

  // 判断用户名是否存在
  private async userSearch(ctxModel, label, name) {
    let exist = await ctxModel.findOne({
      where: {
        [label]: name
      }
    });
    return exist ? true : false;
  }

  // 判断邮箱是否存在

  /**
   * @api {get} user/list 获取用户列表
   *  
   * @apiName list
   * @apiGroup User
   * @apiDescription 获取用户列表
   *  @apiHeaderExample {json} headers:
   *     {
   *       "token": "admin_token"
   *     }
   *
   * @apiParam {String} name 用户名
   * @apiParam {String} level 等级
   * @apiParam {String} status 状态(-1 全部 1-启用 0-停用)
   * @apiParam {String} [pageNo] 页码
   * @apiParam {String} [pageSize] 页数
   *
   */
  public async list(ctx) {
    let searchObj = {};
    let { name, level, status, pageNo, pageSize } = ctx.request.query;
    if (name !== undefined && name !== '') {
      searchObj = Object.assign(searchObj, {
        name: {
          [Op.like]: `%${name}%`
        }
      });
    }
    let { offset, limit } = ctx.helper.changePage(pageNo, pageSize);
    if (level !== undefined && level !== '') {
      searchObj = Object.assign(searchObj, {
        level: parseInt(level)
      });
    }
    if (status !== undefined && status !== '' && status !== -1 && status !== '-1') {
      searchObj = Object.assign(searchObj, {
        status: parseInt(status)
      });
    }
    await ctx.model.User.findAndCountAll({
      where: Object.assign(searchObj),
      offset: offset,
      limit: limit
    })
      .then(users => {
        ctx.response.body = {
          code: 200,
          data: users.rows,
          total: users.count,
          status: '成功'
        };
      });
  }

  /**
   * @api {post} user/add 添加用户
   *  
   * @apiName add
   * @apiGroup User
   * @apiDescription 添加用户,默认密码123456
   *  @apiHeaderExample {json} headers:
   *     {
   *       "token": "admin_token"
   *     }
   *
   * @apiParam {String} name 用户名
   * @apiParam {String} [nickname] 用户昵称
   * @apiParam {String} score 积分
   * @apiParam {String} level 等级
   * @apiParam {String} status 状态(1-启用 0-禁用)
   * @apiParam {String} phone 电话
   * @apiParam {String} email 邮箱
   * @apiParam {String} moneys 金额
   * @apiParam {String} roleId 角色ID
   *
   */
  public async add() {
    const ctx = this.ctx;
    let {
      name,
      nickname,
      score,
      level,
      status,
      phone,
      email,
      moneys,
      roleId }
      = ctx.request.body;
    try {
      if (nickname === undefined || nickname !== '') {
        nickname = name;
      }

      let is_exist = await ctx.model.User.findOne({
        where: {
          name: name
        }
      });
      if (is_exist) {
        throw this.ctx.helper.getErrorMsg(215);
      }
      let md5_password = CryptoJS.MD5('123456').toString();
      let user = await ctx.model.User.create({
        name: name,
        nickname: nickname,
        password: md5_password,
        score: score,
        phone: phone,
        email: email,
        level: level,
        status: status,
        moneys: moneys,
        roleId: roleId
      });
      ctx.response.body = {
        code: 200,
        data: user,
        status: '成功'
      };
    } catch (error) {
      ctx.response.body = error;
    }

  }

  /**
   * @api {post} user/update 修改用户
   *  
   * @apiName update
   * @apiGroup User
   * @apiDescription 修改用户
   *  @apiHeaderExample {json} headers:
   *     {
   *       "token": "admin_token"
   *     }
   *
   * @apiParam {String} name 用户名
   * @apiParam {String} nickname 昵称
   * @apiParam {String} score 积分
   * @apiParam {String} level 等级
   * @apiParam {String} phone 电话
   * @apiParam {String} email 邮箱
   * @apiParam {String} moneys 金额
   * @apiParam {String} roleId 角色ID
   *
   */
  public async update() {
    let {
      id,
      nickname,
      score,
      level,
      phone,
      email,
      moneys,
      roleId
    } = this.ctx.request.body;
    const ctx = this.ctx;
    try {
      await ctx.model.User.update({
        nickname: nickname,
        phone: phone,
        email: email,
        score: score,
        level: level,
        moneys: moneys,
        roleId: roleId
      }, {
        where: {
          id: parseInt(id)
        }
      });
      ctx.response.body = {
        code: 200,
        status: '成功'
      };
    } catch (info) {
      console.log(info);
    }

  }

  /**
   * @api {post} user/changeStatus 变更用户状态
   *  
   * @apiName changeStatus
   * @apiGroup User
   * @apiDescription 变更用户状态
   *  @apiHeaderExample {json} headers:
   *     {
   *       "token": "admin_token"
   *     }
   *
   * @apiParam { String } id 用户id
   * @apiParam { String } status 状态(1 - 启用 0 - 禁用)
   * 
   */
  public async changeStatus(ctx) {
    let { id, status } = ctx.request.body;
    await ctx.model.User.update({
      status: parseInt(status)
    }, {
      where: {
        id: parseInt(id)
      }
    });

    ctx.response.body = {
      code: 200,
      status: '用户修改成功'
    }
  }

  /**
   * @api {post} user/updatePassword 修改用户密码 
   *  
   * @apiName updatePassword
   * @apiGroup User
   * @apiDescription 修改用户
   *  @apiHeaderExample {json} headers:
   *     {
   *       "token": "user_token"
   *     }
   *
   * @apiParam {String} userId 用户id
   * @apiParam {String} newPassword 新设置的密码
   *
   */
  public async updatePassword() {
    let { userId, newPassword } = this.ctx.request.body;
    try {
      if (!userId || userId === '' || !newPassword || newPassword === '') {
        throw this.ctx.helper.getErrorMsg(207);
      }
      let md5_password = CryptoJS.MD5(newPassword).toString();
      await this.ctx.model.User.update({
        password: md5_password
      }, {
        where: {
          id: parseInt(userId)
        }
      });
      this.ctx.response.body = {
        code: 200,
        status: '成功'
      }
    } catch (data) {
      this.ctx.response.body = data;
    }

  }

  /**
   * @api {post} user/delete 删除用户
   *  
   * @apiName delete
   * @apiGroup User
   * @apiDescription 删除用户,ids可接受字符串，字符串为删除单个用户
   * @apiHeaderExample {json} headers:
   *     {
   *       "token": "admin_token"
   *     }
   *
   * @apiParam {Array} ids 用户ID
   */
  public async delete(ctx) {
    let { ids } = ctx.request.body;
    try {
      if (ids === undefined || ids === '' || ids === []) {
        throw ctx.helper.getErrorMsg(207);
      }
      let queryArray: number[] = [];
      let postType = await ctx.helper.whatType(ids);
      if (postType === 'String' || postType === 'Number') {
        queryArray.push(parseInt(ids));
      } else if (postType === 'Array') {
        ids.forEach(id => {
          queryArray.push(parseInt(id));
        });
      }
      await ctx.model.User.destroy({
        where: {
          id: {
            [Op.or]: queryArray
          }
        }
      })
        .then(() => {
          ctx.response.body = {
            code: 200,
            status: '成功'
          };
        });
    } catch (info) {
      ctx.response.body = info;
    }

  }

  /**
   * @api {get} user/getCurrentUser 获取当前用户信息
   *  
   * @apiName current_user
   * @apiGroup User
   * @apiDescription 获取当前用户信息
   * @apiHeaderExample {json} headers:
   *     {
   *       "token": "admin_token"
   *     }
   */
  public async getCurrent() {
    let token = this.ctx.request.headers.token;
    let cry_obj = CryptoJS.AES.decrypt(token, 'sharesites');
    let info_obj = cry_obj.toString(CryptoJS.enc.Utf8);
    let create_real_obj = JSON.parse(JSON.stringify(info_obj));
    create_real_obj = JSON.parse(create_real_obj);
    let info = await this.ctx.model.User.findOne({
      where: {
        name: create_real_obj.name
      },
      attributes: {
        exclude: ['password', 'createdAt', 'updatedAt'],
      },
    });
    this.ctx.response.body = {
      code: 200,
      data: info,
      status: '成功'
    }
  }

  /**
   * @api {get} user/canRegister 判断是否可以进行用户名注册
   *  
   * @apiName canRegister
   * @apiGroup User
   * @apiDescription 判断是否可以进行用户名注册，可以为true,否则为false
   * 
   * @apiParam {String} name 用户名
   */
  public async canRegister(ctx) {
    let { name } = ctx.request.query;

    const count = await this.userSearch(ctx.model.User, 'name', name);
    if (!count) {
      ctx.response.body = {
        code: 200,
        data: true,
        status: '该用户名未被注册'
      }
    } else {
      ctx.response.body = ctx.helper.getErrorMsg(213);
    }
  }

  /**
   * @api {get} user/getAdminLoginHistory 获取后台登陆角色的记录
   *  
   * @apiName getAdminLoginHistory
   * @apiGroup User
   *  @apiHeaderExample {json} headers:
   *     {
   *       "token": "admin_token"
   *     }
   * @apiDescription 获取后台登陆角色的记录,最多只显示十条数据
   */
  public async getAdminLoginHistory(ctx) {
    let data = await this.app.redis.lrange('adminLoginMessage', 0, 10);
    let returnArray: any = [];
    data.forEach(item => {
      let cry_obj = CryptoJS.AES.decrypt(item, 'sharesites');
      let info_obj = cry_obj.toString(CryptoJS.enc.Utf8);
      let create_real_obj = JSON.parse(JSON.stringify(info_obj));
      create_real_obj = JSON.parse(create_real_obj);
      returnArray.push(create_real_obj);
    });
    returnArray = returnArray.map(item => {
      return {
        name: item.name,
        time: item.time
      }
    });
    ctx.response.body = {
      code: 200,
      data: returnArray,
      status: '成功'
    }
  }

  /**
   * @api {get} user/download 获取文章可下载资源链接
   *  
   * @apiName download
   * @apiGroup User
   *  @apiHeaderExample {json} headers:
   *     {
   *       "token": "user_token"
   *     }
   * @apiDescription 获取文章可下载资源链接
   * @apiParam {String} articleId 文章的ID
   * @apiParam {String} type 下载资源的种类
   */
  public async download() {
    try {
      let data = userMsg(this.ctx);
      let currentUserRoleLimit = await this.app.redis.hget('visitMax', `${data.roleId}`);
      let val = await this.app.redis.hget('common-' + data.name, 'download');
      if (parseInt(`${val}`) + 1 > parseInt(`${currentUserRoleLimit}`)) {
        throw this.ctx.helper.getErrorMsg(214);
      }
      if (val) {
        await this.app.redis.hset('common-' + data.name, 'download', parseInt(val) + 1);
      } else {
        await this.app.redis.hset('common-' + data.name, 'download', 1);
      }

      this.ctx.response.body = {
        code: 200,
        status: '成功'
      }
    } catch (info) {
      this.ctx.response.body = info;
    }

  }

  /**
   * @api {post} user/login 前台用户登录
   *  
   * @apiName login
   * @apiGroup User
   * @apiDescription 前台用户登录
   * @apiParam {String} name 用户名
   * @apiParam {String} password 密码
   * @apiParam {String} validateCode 验证码
   */
  public async login() {
    try {
      let { name, password, validateCode } = this.ctx.request.body;
      let md5_password = CryptoJS.MD5(password).toString();
      let info = await this.ctx.model.User.findOne({
        where: {
          name: name,
          password: md5_password
        }
      });
      // 用户是否存在
      if (!info) {
        this.ctx.logger.warn('info into');
        throw this.ctx.helper.getErrorMsg(211);
      }
      // 提交的验证码与session保存的验证码是否一致
      if (!Object.is(validateCode, (this.ctx.session.userInfo.loginCode).toLowerCase())) {
        throw this.ctx.helper.getErrorMsg(208);
      }

      // 校验当前用户的状态是否被禁用
      if (Object.is(info.dataValues.status, 0)) {
        throw this.ctx.helper.getErrorMsg(204);
      }
      let token_json = {
        limit: info.dataValues.limit || '',
        name: info.dataValues.name,
        time: moment().format('YYYY-MM-DD HH:mm:ss'),
        portrait: info.dataValues.portrait
      }
      let user_token = CryptoJS.AES.encrypt(JSON.stringify(token_json), 'sites');
      // 同个用户同时只可以登录一次,用来禁止账号多人同时登录
      // await this.app.redis.hset('user_login_token', name, user_token);
      this.ctx.response.body = {
        code: 200,
        data: `${user_token}`,
        status: '登录成功'
      }
    } catch (error_info) {
      this.ctx.response.body = error_info;
    }
  }

  /**
   * @api {post} user/register 前台用户注册
   *  
   * @apiName register
   * @apiGroup User
   * @apiDescription 前台用户注册,邮件发送到指定邮箱,必须校验邮箱的唯一性
   * @apiParam {String} name 用户名
   * @apiParam {String} nickname 昵称
   * @apiParam {String} password 密码
   * @apiParam {String} email 邮箱
   * @apiParam {String} inviteCode 邀请码
   */
  public async register() {
    let { name, nickname, password, email, inviteCode } = this.ctx.request.body;
    try {
      let app: any = this.app;
      const configUrl = `http://${app.getIP()}:7001/font/getConfig`;
      let res = await superagent.get(configUrl)
      let { data: configData } = res.body;
      const mustInvite = configData.inviteCode === 'true' ? true : false;
      if (mustInvite && (!inviteCode || inviteCode === '')) {
        throw this.ctx.helper.getErrorMsg(226);
      }
      const { url } = envConfig(this.app.config.env);

      if (!name) {
        throw this.ctx.helper.getErrorMsg(219);
      }

      if (!nickname) {
        nickname = name;
      }

      if (!password) {
        throw this.ctx.helper.getErrorMsg(219);
      }

      const exitsName = await this.userSearch(this.ctx.model.User, 'name', name);
      if (exitsName) {
        throw this.ctx.helper.getErrorMsg(213);
      }

      // 校验邮箱的唯一性
      const existEmail = await this.userSearch(this.ctx.model.User, 'email', email);
      if (existEmail) {
        throw this.ctx.helper.getErrorMsg(228);
      }

      const createTime = moment().format('YYYY-MM-DD HH:mm:ss');

      let userInfo = {
        name: name,
        password: password,
        email: email,
        time: createTime
      };

      // 设置缓存用户发送邮件时间
      await this.app.redis.hset('userRegisterTime', name, moment().format('YYYY-MM-DD HH:mm:ss'));

      // AES加密信息
      let userInfoEncryt = CryptoJS.AES.encrypt(JSON.stringify(userInfo), 'user_info');

      let emailContent = artTemplate(path.join(__dirname, '../template/register.art'), {
        username: name,
        time: createTime,
        address: 'IT优资社区',
        link: `${url}/user/registerSuccess?params=${encodeURIComponent(userInfoEncryt)}`
      });

      await this.ctx.service.tools.email({
        revicer: email,
        title: '注册信息',
        content: emailContent
      });
      this.ctx.response.body = {
        code: 200,
        status: '请确认邮件，完成注册'
      };
    } catch (error_info) {
      this.ctx.response.body = error_info;
    }
  }

  /**
   * @api {post} user/emailConfirm 前台用户邮件确认
   *  
   * @apiName emailConfirm
   * @apiGroup User
   * @apiDescription 用户对前台用户注册信息进行确认，完成最后的用户注册流程
   * @apiParam {String} name 注册用户名
   * @apiParam {String} email 注册邮箱
   * @apiParam {String} password 注册用户密码
   */
  public async emailConfirm(ctx) {
    let body = ctx.request.body;
    try {
      const type = await ctx.helper.whatType(body);
      if (!Object.is(type, 'Object')) {
        throw ctx.helper.getErrorMsg(207);
      }
      let { password = '', name = '' } = body;
      body.password = CryptoJS.MD5(password).toString();
      if (!body.hasOwnProperty('nickname')) {
        body.nickname = body.name;
      }
      let is_exist_user = await ctx.model.User.findOne({
        where: {
          name: name,
        }
      });
      if (!is_exist_user) {
        let getRole = await ctx.model.Role.findOne({
          where: {
            name: 'normalUser'
          }
        });
        const randomNumber: any = Math.random() * 5;
        await this.app.redis.hdel('userRegisterTime', name);
        await ctx.model.User.create(Object.assign({
          level: 1,
          roleId: parseInt(getRole.roleId),
          portrait: `static/images/internal/${parseInt(randomNumber, 10)}.jpg`
        }, body));
        ctx.response.body = {
          code: 200,
          token: 1,
          status: '成功'
        };
      } else {
        throw ctx.helper.getErrorMsg(213);
      }
    } catch (error_info) {
      // console.log('error_info', error_info);
      ctx.response.body = error_info;
    }
  }

}
